package com.zidongxiangxi.clock.server.manager;

import com.zidongxiangxi.clock.server.job.AbstractWorkThread;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 闹钟任务线程管理类
 *
 * @author chenxudong
 * @date 2020/07/23
 */
@Slf4j
@Component
public class ClockWorkThreadManger {

    private final List<AbstractWorkThread> threads;

    private static final int MAX_SHUTDOWN_RETRY_TIMES = 3;

    private final AtomicBoolean stop = new AtomicBoolean(false);

    private final ExecutorService WORK_THREAD_POOL =
        new ThreadPoolExecutor(8, 8, 10, TimeUnit.SECONDS, new ArrayBlockingQueue<>(4),
            new ThreadFactoryBuilder().setNameFormat("work-thread-%d").build());

    public ClockWorkThreadManger(List<AbstractWorkThread> threads) {
        this.threads = threads;
    }

    public void start() {
        log.info("AlarmClockDaemonWorkThread run ....");
        for (AbstractWorkThread thread : threads) {
            WORK_THREAD_POOL.submit(thread);
        }
    }

    public void stopWorkThread() {
        if (!stop.compareAndSet(false, true)) {
            log.error("AlarmClockWorkThread is stop, do not need to stop again");
            return;
        }
        log.info("stop AlarmClockWorkThread ....");
        for (AbstractWorkThread thread : threads) {
            thread.stop();
        }
        WORK_THREAD_POOL.shutdown();
        int retryTimes = 0;
        while (retryTimes < MAX_SHUTDOWN_RETRY_TIMES && !WORK_THREAD_POOL.isTerminated()) {
            retryTimes++;
            try {
                boolean termination = WORK_THREAD_POOL.awaitTermination(3, TimeUnit.SECONDS);
                if (termination) {
                    break;
                }
            } catch (InterruptedException ignore) {
                Thread.currentThread().interrupt();
            }
        }
    }

}
